package cn.iocoder.yudao.module.diy.service.diy;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.diy.controller.admin.diy.vo.other.*;
import cn.iocoder.yudao.module.diy.controller.admin.diy.vo.page.DiyPagePageReqVO;
import cn.iocoder.yudao.module.diy.controller.admin.page.vo.PagePageReqVO;
import cn.iocoder.yudao.module.diy.dal.dataobject.addon.AddonDO;
import cn.iocoder.yudao.module.diy.dal.dataobject.page.PageDO;
import cn.iocoder.yudao.module.diy.dal.diy.*;
import cn.iocoder.yudao.module.diy.dal.mysql.page.PageMapper;
import cn.iocoder.yudao.module.diy.enums.SceneDomainVo;
import cn.iocoder.yudao.module.diy.enums.TemplateEnum;
import cn.iocoder.yudao.module.diy.exception.CommonException;
import cn.iocoder.yudao.module.diy.service.addon.AddonService;
import cn.iocoder.yudao.module.diy.service.diyroute.DiyRouteService;
import cn.iocoder.yudao.module.diy.utils.RequestUtils;
import cn.iocoder.yudao.module.diy.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.Binder;
import java.math.BigDecimal;
import java.util.*;


/**
 * 自定义页面实现类
 */
@Service
public class DiyServiceImpl implements IDiyService {

    @Resource
    PageMapper pageMapper;


    @Resource
    ICoreDiyConfigService coreDiyConfigService;

    @Resource
    DiyRouteService diyRouteService;
    @Resource
    AddonService addonService;

    /**
     * 自定义页面分页列表
     *
     * @param pageReqVO 分页参数
     * @return PageResult<NsDiyPageRespVo>
     */
    @Override
    public PageResult<NsDiyPageRespVo> nsPageList(DiyPagePageReqVO pageReqVO) {
        PageResult<PageDO> targetList = pageMapper.selectPage2(pageReqVO);
        PageResult<NsDiyPageRespVo> result = new PageResult<>();
        BeanUtils.copyProperties(targetList, result);
        JSONObject template = TemplateEnum.getTemplate();
        List<NsDiyPageRespVo> list = new LinkedList<>();
        for (PageDO page : targetList.getList()) {
            NsDiyPageRespVo vo = new NsDiyPageRespVo();
            BeanUtils.copyProperties(page, vo);
            vo.setAddonName(page.getAddonKey());
            vo.setType(page.getPageType());
            vo.setTypeName(ObjectUtil.defaultIfNull(template.getByPath(vo.getType() + ".title", String.class), ""));
            vo.setTypePage(ObjectUtil.defaultIfNull(template.getByPath(vo.getType() + ".page", String.class), ""));
            list.add(vo);
        }
        result.setList(list);
        return result;
    }

    /**
     * 自定义页面列表
     *
     * @param pageVO
     * @return
     */
    public List<NsDiyPageRespVo> allList(DiyPagePageReqVO pageVO) {
        List<NsDiyPageRespVo> result = null;
        List<PageDO> list = pageMapper.selectList(new LambdaQueryWrapperX<PageDO>()
                .likeIfPresent(PageDO::getPageName, pageVO.getName())
                .eqIfPresent(PageDO::getPageType, pageVO.getType())
                .eqIfPresent(PageDO::getMode, pageVO.getMode())
                .betweenIfPresent(PageDO::getCreateTime, pageVO.getCreateTime())
                // 模板下面的页面，在模板中管理
                .orderByDesc(PageDO::getId));
        if (null != list) {
            for (PageDO d : list) {
                NsDiyPageRespVo vo = new NsDiyPageRespVo();
                BeanUtils.copyProperties(d, vo);
                result.add(vo);
            }
        }
        return result;
    }

    /**
     * 自定义页面详情
     *
     * @param id 主键参数
     * @return DiyPage
     */
    @Override
    public NsDiyPageRespVo info(Long id) {
        PageDO model = pageMapper.selectOne(
                new QueryWrapper<PageDO>()
                        .eq("id", id));

        if (model == null) return null;

        NsDiyPageRespVo vo = new NsDiyPageRespVo();
        BeanUtils.copyProperties(model, vo);
        vo.setName(model.getPageName());
        vo.setPageTitle(model.getPageTitle());
        vo.setValue(model.getPageValue());
        vo.setTypeName(model.getPageType());
        vo.setType(model.getPageType());
        return vo;
    }

    @Override
    public NsDiyPageRespVo infoByName(String name) {
        PageDO model = pageMapper.selectOne(
                new QueryWrapper<PageDO>()
                        .eq("page_name", name)
                        .eq("is_default", 1));

        if (model == null) return null;

        NsDiyPageRespVo vo = new NsDiyPageRespVo();
        BeanUtils.copyProperties(model, vo);
        vo.setName(model.getPageName());
        vo.setPageTitle(model.getPageTitle());
        vo.setValue(model.getPageValue());
        vo.setTypeName(model.getPageType());
        vo.setType(model.getPageType());

        return vo;
    }

    /**
     * 自定义页面新增
     *
     * @param param 参数
     */
    @Override
    public void syncAdd(DiyPageParam param) {
        List<AddonDO> addonList = addonService.getAddonList(new AddonDO().setAddonKey(param.getAddonKey()));
        for (AddonDO item : addonList) {
            PageDO model = new PageDO();
            BeanUtils.copyProperties(param, model);
            model.setAddonId(item.getId());
            pageMapper.insert(model);
        }
    }

    /**
     * 自定义页面新增
     *
     * @param param 参数
     */
    @Override
    public Long add(DiyPageParam param) {
        List<AddonDO> addonList = addonService.getAddonList(new AddonDO().setAddonKey(param.getAddonKey()));
        for (AddonDO item : addonList) {
            PageDO model = new PageDO();
            BeanUtils.copyProperties(param, model);
            model.setAddonId(item.getId());
            pageMapper.insert(model);
        }
        return 1l;
    }

    /**
     * 自定义页面编辑
     *
     * @param id 参数
     */
    @Override
    public void edit(Long id, DiyPageParam editParam) {
        PageDO model = pageMapper.selectOne(
                new QueryWrapper<PageDO>()
                        .eq("id", id));

        Assert.notNull(model, "数据不存在!");

        BeanUtils.copyProperties(editParam, model);
        pageMapper.updateById(model);
    }

    /**
     * 自定义页面删除
     *
     * @param id 主键ID
     */
    @Override
    public void del(Long id) {
        pageMapper.delete(new QueryWrapper<PageDO>().eq("id", id).eq("site_id", TenantContextHolder.getTenantId()));
    }

    /**
     * 设为使用
     *
     * @param id
     */
    public void setUse(Long id) {
        PageDO model = pageMapper.selectOne(
                new QueryWrapper<PageDO>()
                        .eq("id", id)
                        .eq("site_id", TenantContextHolder.getRequiredTenantId()));
        Assert.notNull(model, "页面不存在!");

        PageDO update = new PageDO();
        update.setIsDefault(0);
        pageMapper.update(update, new QueryWrapper<PageDO>().eq("name", model.getPageName()).eq("site_id", TenantContextHolder.getTenantId()));

        update.setId(id.longValue());
        update.setIsDefault(1);
        pageMapper.updateById(update);
    }


    public JSONObject getLink() {
        JSONObject linkEnum = LinkEnum.getLink();
        for (String key : linkEnum.keySet()) {

            if (key.equals("DIY_PAGE")) {
                List<PageDO> pageList = this.pageMapper.selectList(new QueryWrapper<PageDO>()
                        .eq("site_id", TenantContextHolder.getTenantId())
                        .eq("page_type", "DIY_PAGE")
                        .or()
                        .ne("page_type", "DIY_PAGE")
                        .eq("site_id", TenantContextHolder.getTenantId())
                        .eq("is_default", 0));

                List<JSONObject> childList = new LinkedList<>();
                for (PageDO item : pageList) {
                    JSONObject page = new JSONObject();
                    page.put("name", item.getPageName());
                    page.put("title", item.getPageTitle());
                    page.put("url", "/app/pages/index/diy?id=" + item.getId());
                    childList.add(page);
                }
                linkEnum.putByPath("DIY_PAGE.child_list", childList);
            }
            if (key.equals("DIY_LINK")) {
                linkEnum.putByPath("DIY_LINK.parent", "DIY_LINK");
            }
        }
        return linkEnum;
    }

    /**
     * 获取自定义链接列表
     *
     * @param param
     */
    public NsDiyPageRespVo getPageInit(DiyPageInitParam param) {
        JSONObject template = getTemplate(new TemplateParam());
        NsDiyPageRespVo info = null;
        if (param.getId() > 0) {
            info = this.info(param.getId().longValue());
        } else if (!param.getName().isEmpty()) {
            info = this.infoByName(param.getName());
        }
        if (!param.getName().isEmpty()) {
            StartUpPageConfigVo startConfig = coreDiyConfigService.getStartUpPageConfig(TenantContextHolder.getTenantId(), param.getName());
            if (startConfig != null) {
                if (startConfig.getParent().equals("DIY_PAGE")) {
                    Integer id = Integer.parseInt(startConfig.getPage().replace("/app/pages/index/diy?id=", ""));
                    info = this.info(id.longValue());
                    if (info != null) {
                        param.setType(info.getType());
                        param.setName(info.getName());
                    }
                } else {
                    for (String key : template.keySet()) {
                        if (ObjectUtil.defaultIfNull(template.getByPath(key + ".page", String.class), "").equals(startConfig.getPage())) {
                            info = this.infoByName(key);
                            if (info != null) {
                                param.setType(key);
                                param.setName(key);
                            }
                            break;
                        }
                    }
                }
            }
        }

        if (info != null) {
            if (template.getJSONObject(info.getType()) != null) {
                JSONObject page = template.getJSONObject(info.getType());
                info.setTypeName(page.getStr("title"));
                info.setPage(page.getStr("page"));
            }
        } else {
            Long time = System.currentTimeMillis() / 1000;
            String pageTitle = ObjectUtil.defaultIfBlank(param.getTitle(), "页面" + time);
            String type = ObjectUtil.defaultIfBlank(param.getType(), "DIY_PAGE");
            String name = type.equals("DIY_PAGE") ? "DIY_PAGE_RANDOM_" + time : type;
            String typeName = "默认面";
            String templateName = "默认版";
            String pageRoute = "";
            String mode = "diy";
            Integer isDefault = 0;
            String value = "";

            JSONObject page = null;
            if (template.getJSONObject(param.getName()) != null) {
                page = template.getJSONObject(param.getName());
                type = name = page.getStr("type");
                pageTitle = typeName = page.getStr("title");
                pageRoute = page.getStr("page");
                JSONObject pageData = this.getFirstPageData(param.getName(), "");
                if (pageData != null) {
                    mode = pageData.getByPath("mode", String.class);
                    value = pageData.getJSONObject("data").toString();
                    isDefault = 1;
                }
            } else if (template.getJSONObject(param.getType()) != null) {
                page = template.getJSONObject(param.getType());
                typeName = page.getStr("title");
                pageRoute = page.getStr("page");
            }

            info = new NsDiyPageRespVo();
            info.setName(name);
            info.setPageTitle(pageTitle);
            info.setTitle(pageTitle);
            info.setType("DIY_PAGE1");
            info.setTypeName(typeName);
            info.setTemplate(templateName);
            info.setPage(pageRoute);
            info.setMode(mode);
            info.setValue(value);
            info.setIsDefault(isDefault);
        }
        info.setComponent(getComponentList(info.getType()));
        SceneDomainVo v = getSceneDomain();
        info.setDomainUrl(v);
        return info;
    }

    @Override
    public SceneDomainVo getSceneDomain() {
        SceneDomainVo result = new SceneDomainVo();
//        result.setWapDomain("http://47.109.51.45");
//        result.setWapUrl(" https://s"+TenantContextHolder.getTenantId()+".meton.vip");
//        result.setWebUrl("https://s"+TenantContextHolder.getTenantId()+".meton.vip/web");
        HttpServletRequest request = RequestUtils.handler();
        result.setWapDomain("http://" + request.getServerName());
        result.setWapUrl("http://" + request.getServerName() + ":5173");
        result.setWebUrl("http://" + request.getServerName());
        return result;
    }

    public JSONObject getComponentList(String type) {

        JSONObject ComponentList = ComponentEnum.getComponent();
        for (String formComponentObj : ComponentList.keySet()) {
            JSONObject formComponent = ComponentList.getJSONObject(formComponentObj);
            ;
            JSONObject list = formComponent.getJSONObject("list");
            Iterator<Map.Entry<String, Object>> iterator = list.entrySet().iterator();
            while (iterator.hasNext()) {
                JSONObject cv = JSONUtil.parseObj(iterator.next());
                if (cv.containsKey("support")) {
                    JSONArray support = cv.getJSONArray("support");
                    if (ObjectUtil.isNotEmpty(type)) {
                        if (support != null && support.size() > 0 && !support.contains(type)) {
                            iterator.remove();
                            continue;
                        }
                    }

                }
                cv.remove("sort");
                cv.remove("support");
            }
            // 根据 sort 排序
            formComponent.put("list", sortJSONObjectBySortField(list));
        }

        return ComponentList;
    }

    private JSONObject sortJSONObjectBySortField(JSONObject originalJsonObject) {
        // 提取所有内部 JSONObject 到一个 List 中
        List<Map.Entry<String, Object>> entryList = new ArrayList<>(originalJsonObject.entrySet());

        // 对 List 进行排序
        Collections.sort(entryList, new Comparator<Map.Entry<String, Object>>() {
            public int compare(Map.Entry<String, Object> o1, Map.Entry<String, Object> o2) {
                JSONObject jsonObj1 = (JSONObject) o1.getValue();
                JSONObject jsonObj2 = (JSONObject) o2.getValue();
                int sort1 = jsonObj1.getInt("sort");
                int sort2 = jsonObj2.getInt("sort");
                return Integer.compare(sort1, sort2);
            }
        });

        // 创建一个新的 JSONObject 来存放排序后的结果
        JSONObject sortedJsonObject = new JSONObject();
        for (Map.Entry<String, Object> entry : entryList) {
            sortedJsonObject.put(entry.getKey(), entry.getValue());
        }

        return sortedJsonObject;
    }

    /**
     * 获取默认页面数据
     *
     * @param type
     * @param addon
     * @return
     */
    public JSONObject getFirstPageData(String type, String addon) {
        JSONObject pages = PagesEnum.getPagesByAddon(type);
        if (pages == null || pages.keySet().size() == 0) return null;

        String template = pages.keySet().iterator().next();
        JSONObject data = pages.getJSONObject(template);
        data.set("type", type);
        data.set("template", template);

        return data;
    }

    /**
     * 获取页面模板
     *
     * @return
     */
    public JSONObject getTemplate(TemplateParam param) {
        if(null==param.getTenantId()){
            param.setTenantId(TenantContextHolder.getTenantId());
        }
        JSONObject template = TemplateEnum.getTemplate(param);
        for (String key : template.keySet()) {
            JSONObject pages = ObjectUtil.defaultIfNull(PagesEnum.getPages(key, param.getMode()), new JSONObject());
            template.putByPath(key + ".template", pages);
        }
        return template;
    }

    /**
     * 设置启动页
     *
     * @param value
     */
    public void changeTemplate(StartUpPageConfigParam value) {
        if(value.getTenantId()==null){
            value.setTenantId(TenantContextHolder.getTenantId());
        }
        this.coreDiyConfigService.setStartUpPageConfig(value.getTenantId(),value.getAddonId(), value.getSiteId(),value, value.getType());
    }

    /**
     * 获取装修页面列表
     *
     * @param searchParam
     */
    public JSONObject getDecoratePage(DiyPageSearchParam searchParam) {
        TemplateParam templateParam = new TemplateParam();
        String[] key = {searchParam.getType()};
        templateParam.setKey(key);
        JSONObject template = this.getTemplate(templateParam).getJSONObject(searchParam.getType());
        if (template == null) throw new CommonException("模板不存在");

        JSONObject defaultPage = getFirstPageData(searchParam.getType(), "");

        JSONObject useTemplate = new JSONObject();
        useTemplate.put("type", searchParam.getType());
        useTemplate.put("title", defaultPage == null ? "" : defaultPage.getStr("title", ""));
        useTemplate.put("name", "");
        useTemplate.put("cover", defaultPage == null ? "" : defaultPage.getStr("cover", ""));
        useTemplate.put("page", template.getStr("page"));
        useTemplate.put("action", template.getStr("action"));
        useTemplate.put("url", "");
        useTemplate.put("parent", "");

        NsDiyPageRespVo info = infoByName(searchParam.getType());


        //获取启动配置
        StartUpPageConfigVo startConfig = coreDiyConfigService.getStartUpPageConfig(TenantContextHolder.getTenantId(), searchParam.getType());
        if (startConfig != null) {
            useTemplate.set("title", startConfig.getTitle());
            useTemplate.set("name", startConfig.getName());
            useTemplate.set("page", startConfig.getPage());
            useTemplate.set("action", startConfig.getAction());
            useTemplate.set("url", startConfig.getPage());
            useTemplate.set("parent", startConfig.getParent());
        } else if (info != null) {
            useTemplate.set("id", info.getId());
            useTemplate.set("title", info.getTitle());
        }
        if (useTemplate.getStr("cover").isEmpty() && useTemplate.getStr("url").isEmpty()) {
            useTemplate.set("url", template.getStr("page"));
        } else if (useTemplate.getStr("url").isEmpty()) {
            useTemplate.set("url", template.getStr("page"));
        }

        DiyRouteSearchParam diyRouteSearchParam = new DiyRouteSearchParam();
        diyRouteSearchParam.setUrl(useTemplate.getStr("page"));
        List<DiyRouteListVo> otherPage = diyRouteService.list(diyRouteSearchParam);
        if (otherPage.size() > 0) {
            DiyRouteListVo route = otherPage.get(0);
            useTemplate.set("title", route.getTitle());
            useTemplate.set("name", route.getName());
            useTemplate.set("parent", route.getParent());
            useTemplate.set("action", route.getAction());
        }

        template.put("use_template", useTemplate);

//        SceneDomainVo sceneDomain = coreSysConfigService.getSceneDomain(TenantContextHolder.getTenantId());

        SceneDomainVo v = getSceneDomain();
        JSONObject domainUrl = new JSONObject();
        domainUrl.put("wap_domain", v.getWapDomain());
        domainUrl.put("wap_url", v.getWapUrl());
        domainUrl.put("web_url", v.getWebUrl());
        template.put("domain_url", domainUrl);

        return template;
    }

    /**
     * 获取自定义页面分页列表，轮播搜索组件用
     */
    public PageResult<NsDiyPageRespVo> getPageByCarouselSearch(PagePageReqVO pageReqVO) {
        PageResult<PageDO> targetList = pageMapper.selectPage(pageReqVO);
        PageResult<NsDiyPageRespVo> result = new PageResult<>();
        BeanUtils.copyProperties(targetList, result);
        JSONObject template = TemplateEnum.getTemplate();
        List<NsDiyPageRespVo> list = new LinkedList<>();
        for (PageDO page : targetList.getList()) {
            NsDiyPageRespVo vo = new NsDiyPageRespVo();
            BeanUtils.copyProperties(page, vo);
            vo.setTypeName(ObjectUtil.defaultIfNull(template.getByPath(vo.getType() + ".title", String.class), ""));
            vo.setTypePage(ObjectUtil.defaultIfNull(template.getByPath(vo.getType() + ".page", String.class), ""));
            list.add(vo);
        }
        result.setList(list);
        return result;
//        Integer page = pageParam.getPage();
//        Integer limit = pageParam.getLimit();
//
//        QueryWrapper<NDiyPageDO> queryWrapper = new QueryWrapper<NDiyPageDO>()
//                .eq("site_id", TenantContextHolder.getTenantId())
//                .eq("type", "DIY_PAGE")
//                .notIn("value", Arrays.asList("top_fixed", "right_fixed", "bottom_fixed", "left_fixed", "fixed"))
//                .or()
//                .eq("site_id", TenantContextHolder.getTenantId())
//                .ne("type", "DIY_PAGE")
//                .eq("is_default", 0)
//                .notIn("value", Arrays.asList("top_fixed", "right_fixed", "bottom_fixed", "left_fixed", "fixed"))
//                .orderByDesc("id");
//
//        IPage<NDiyPageDO> iPage = pageMapper.selectPage(new Page<NDiyPageDO>(page, limit), queryWrapper);
//        List<NsDiyPageRespVo> list = new LinkedList<>();
//        for (NDiyPageDO item : iPage.getRecords()) {
//            NsDiyPageRespVo vo = new NsDiyPageRespVo();
//            BeanUtils.copyProperties(item, vo);
//            list.add(vo);
//        }
//        return PageResult.build(page, limit, iPage.getTotal()).setData(list);
    }

    /**
     * 设置 首页/个人中心 的第一个模板 设置为启动页
     *
     * @param param
     */
    public void setDiyData(SetDiyDataParam param) {
        String addonFlag = param.getKey();

        TemplateParam templateParam = new TemplateParam();
        String[] key = {param.getKey()};
        templateParam.setKey(key);
        templateParam.setAddon(param.getAddon());
        JSONObject template = getTemplate(templateParam).getJSONObject(param.getKey());
        if (template == null) return;

        if (!param.getAddon().isEmpty()) {
            TemplateParam addonTemplateParam = new TemplateParam();
            addonTemplateParam.setAddon(param.getAddon());
            addonTemplateParam.setType(param.getType());
            JSONObject addonTemplate = getTemplate(addonTemplateParam);
            if (addonTemplate != null) {
                template = addonTemplate.getJSONObject(addonFlag);
            }
        }

        JSONObject pages = template.getJSONObject("template");
        if (pages.isEmpty()) return;

        String pageKey = pages.keySet().iterator().next();
        JSONObject page = pages.getJSONObject(pageKey);

        PageDO info = pageMapper.selectOne(new QueryWrapper<PageDO>()
                .eq("page_name", addonFlag)
                .eq("site_id", param.getTenantId())
                .eq("is_default", 1)
        );

        if (info == null) {
            DiyPageParam addParam = new DiyPageParam();
            addParam.setTitle(page.getStr("title", ""));
            addParam.setPageTitle(page.getStr("title", ""));
            addParam.setPageName(addonFlag);
            addParam.setPageType(addonFlag);
            addParam.setTemplate(pageKey);
            addParam.setPageValue(page.getJSONObject("data").toString());
            addParam.setMode(page.getStr("mode", ""));
            addParam.setIsDefault(1);
            addParam.setIsChange(0);
            addParam.setTenantId(param.getTenantId());
            addParam.setAddonKey(param.getAddon());
            addParam.setSiteId(param.getSiteId());
            this.syncAdd(addParam);
        } else {
            if (info.getPageName().equals("DIY_INDEX") && info.getPageType().equals("DIY_INDEX")) {
                PageDO update = new PageDO();
                update.setId(info.getId());
                update.setPageValue(page.getJSONObject("data").toString());
                pageMapper.updateById(update);
            }
        }
        if (param.getIsStart().equals(1)) {
            StartUpPageConfigParam startPage = new StartUpPageConfigParam();
            startPage.setType(param.getKey());
            startPage.setMode(page.getStr("mode", ""));
            startPage.setTitle(page.getStr("title", ""));
            startPage.setAction(template.getStr("action", ""));
            startPage.setPage(template.getStr("page"));
            startPage.setTenantId(param.getTenantId());
            startPage.setAddonId(param.getAddonId());
            startPage.setSiteId(param.getSiteId());
            this.changeTemplate(startPage);
        }
    }

    /**
     * 复制
     *
     * @param id
     */
    @Override
    public void copy(Integer id) {
        PageDO page = pageMapper.selectOne(new QueryWrapper<PageDO>().eq("id", id).eq("site_id", TenantContextHolder.getTenantId()));
        if (page == null) throw new CommonException("页面不存在");
        page.setId(null);
        page.setPageTitle(page.getPageTitle() + "_副本");
        page.setIsChange(0);
        page.setIsDefault(0);
        page.setShare("");
        pageMapper.insert(page);
    }
}
